/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package astroim.smack;

import astroim.samp.LocalConnector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.astrogrid.samp.client.SampException;
import org.jivesoftware.smack.PacketInterceptor;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.NodeInformationProvider;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.packet.DiscoverInfo.Identity;
import org.jivesoftware.smackx.packet.DiscoverItems;
import org.jivesoftware.smackx.packet.DiscoverItems.Item;

/**
 *
 * @author alykhalid
 */
public class SrvDisco {

    private Map<String, NodeInformationProvider> nodeInformationProviders = new ConcurrentHashMap<String, NodeInformationProvider>();

    public SrvDisco() {
        try {
            SetupItemNodes();
        } catch (SampException ex) {
            Logger.getLogger(SrvDisco.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("Size: " + nodeInformationProviders.size());

    }

    public XMPPConnection register(final XMPPConnection connection) {
        PacketFilter packetFilter = new PacketTypeFilter(DiscoverItems.class);
        PacketListener packetListener = new PacketListener() {

            public void processPacket(Packet packet) {
                DiscoverItems discoverItems = (DiscoverItems) packet;
                // Send back the items defined in the client if the request is of type GET
                if (discoverItems != null && discoverItems.getType() == IQ.Type.GET) {
                    DiscoverItems response = new DiscoverItems();
                    response.setType(IQ.Type.RESULT);
                    response.setTo(discoverItems.getFrom());
                    response.setPacketID(discoverItems.getPacketID());
                    response.setNode("astronomy");
                    //System.out.println("Node:" + discoverItems.getNode());
                    // Add the defined items related to the requested node. Look for
                    // the NodeInformationProvider associated with the requested node.
                    NodeInformationProvider nodeInformationProvider = getNodeInformationProvider(discoverItems.getNode());
                    if (nodeInformationProvider != null) {
                        System.out.println("Specified node was found");
                        List<DiscoverItems.Item> items = nodeInformationProvider.getNodeItems();
                        if (items != null) {
                            for (DiscoverItems.Item item : items) {
                                response.addItem(item);
                            }
                        }
                    } else /*if(discoverItems.getNode() == null)*/ {
                        // Return <item-not-found/> error since client doesn't contain
                        // the specified node
                        response.setType(IQ.Type.ERROR);
                        response.setError(new XMPPError(XMPPError.Condition.item_not_found));
                        System.out.println("Setting Error Response");
                    }
                    connection.sendPacket(response);
                }
            }
        };
        connection.addPacketListener(packetListener, packetFilter);
        return connection;

    }

    public XMPPConnection IntercepPacket(final XMPPConnection connection) {
        PacketFilter packetFilter = new PacketTypeFilter(DiscoverItems.class);
        PacketInterceptor pi = new PacketInterceptor(){
            public void interceptPacket(Packet packet) {
                System.out.println("Packet: " + packet.toXML());
                DiscoverItems discoverItems = (DiscoverItems) packet;
                if("astronomy".equalsIgnoreCase(discoverItems.getNode())){
                    System.out.println("Astronomy Node");
                    if(discoverItems.getError() != null){
                        System.out.println("Error not null");
                        if("item-not-found(404)".equalsIgnoreCase(discoverItems.getError().toString()))
                            System.out.println("Error Matched");
                            for(String s : packet.getPropertyNames())
                                System.out.println(s);
                    }
                }
            }
        };
        connection.addPacketWriterInterceptor(pi, packetFilter);
        return connection;
    }

    private NodeInformationProvider getNodeInformationProvider(String node) {
        if (node == null) {
            return null;
        }
        return nodeInformationProviders.get(node);
    }

    private void SetupItemNodes() throws SampException {
        final ArrayList<String> items = new ArrayList<String>();
        boolean copy = false;
        String ID = null, Name = null;

        LocalConnector lc = LocalConnector.getInstance();
        LocalConnector registeredClients = lc.registerWithHUb().getRegisteredClients();
        HashMap<Map, Map> ClientMapProperties = registeredClients.ClientMapProperties;
        Iterator itClientMap = ClientMapProperties.entrySet().iterator();
        while (itClientMap.hasNext()) {
            Map.Entry<Map, Map> ClientMapPairs = (Map.Entry<Map, Map>) itClientMap.next();
            Iterator itClientIDMap = ClientMapPairs.getKey().entrySet().iterator();
            while (itClientIDMap.hasNext()) {
                Map.Entry<String, String> ClientIDMapPairs = (Map.Entry<String, String>) itClientIDMap.next();
//                System.out.println("ClientIDMapPairs Key|Value: " + ClientIDMapPairs.getKey() + " | " + ClientIDMapPairs.getValue());
                if ((!LocalConnector.NAME.equals(ClientIDMapPairs.getValue())) && (!"Hub".equals(ClientIDMapPairs.getValue()))) {
                    ID = ClientIDMapPairs.getKey();
                    Name = ClientIDMapPairs.getValue();
                    copy = true;
                }
            }
            Iterator itClientIDMapSideB = ClientMapPairs.getValue().entrySet().iterator();
            while (itClientIDMapSideB.hasNext()) {
                Map.Entry<String, Map> ClientIDMapPairs = (Map.Entry<String, Map>) itClientIDMapSideB.next();
                if(copy){
//                    System.out.println("ClientIDMapPairsSideB Key|Value: " + ClientIDMapPairs.getKey() + " | " + ClientIDMapPairs.getValue());
                    items.add(ID + "/" + Name + "/" + ClientIDMapPairs.getKey());
                }
            }
            copy = false;
            ID="";
            Name="";
        }
        //nodeInformationProviders.put("astronomy", new NodeInformationProviderImpl(items));
        ServiceDiscoveryManager.getInstanceFor(Connection.getInstance().getConnection()).setNodeInformationProvider(
                "astronomy", new NodeInformationProvider(){

            public List<Item> getNodeItems() {
                ArrayList<Item> itemsIN = new ArrayList<Item>();
                int index = 0;
                for (String T : items) {
                    Item i = new Item(Integer.toString(index));
                    i.setName(T);
                    i.setAction(Item.UPDATE_ACTION);
                    itemsIN.add(i);
                    index++;
                }
                return itemsIN;
            }

            public List<String> getNodeFeatures() {
                throw new UnsupportedOperationException("Not supported yet.");
            }

            public List<Identity> getNodeIdentities() {
                throw new UnsupportedOperationException("Not supported yet.");
            }


        });
    }

//    private static class NodeInformationProviderImpl implements NodeInformationProvider {
//
////        private final Entry<Map, Map> ClientMapPairs;
////        private final Entry<String, String> ClientIDMapPairs;
//       private final ArrayList<String> Items;
//
////        public NodeInformationProviderImpl(Entry<Map, Map> ClientMapPairs, Entry<String, String> ClientIDMapPairs) {
////            this.ClientMapPairs = ClientMapPairs;
////            this.ClientIDMapPairs = ClientIDMapPairs;
////        }
//
//        private NodeInformationProviderImpl(ArrayList<String> items) {
//            this.Items = items;
//        }
//
//        public List<Item> getNodeItems() {
//            ArrayList<Item> items = new ArrayList<Item>();
//            int index = 0;
//            for(String T : Items){
//                Item i = new Item(Integer.toString(index));
//                i.setName(T);
//                i.setAction(Item.UPDATE_ACTION);
//                items.add(i);
//                index++;
//            }
//
//            //System.out.println("Size of ClientMapPairs: " + ClientMapPairs.getValue().entrySet().size());
////            Iterator itSubscriptionMap = ClientMapPairs.getValue().entrySet().iterator();
////            int index = 0;
////            while (itSubscriptionMap.hasNext()) {
////                Map.Entry SubscriptionMapPairs = (Map.Entry) itSubscriptionMap.next();
////                System.out.println(ClientIDMapPairs.getKey() + "/" + ClientIDMapPairs.getValue() + "/" + SubscriptionMapPairs.getKey());
////                Item i = new Item(Integer.toString(index));
////                i.setName(ClientIDMapPairs.getKey() + "/" + ClientIDMapPairs.getValue() + "/" + SubscriptionMapPairs.getKey());
////                i.setAction(Item.UPDATE_ACTION);
////                items.add(i);
////                index++;
////            }
//            return items;
//        }
//
//        public List<String> getNodeFeatures() {
//            throw new UnsupportedOperationException("Not supported yet.");
//        }
//
//        public List<Identity> getNodeIdentities() {
//            throw new UnsupportedOperationException("Not supported yet.");
//        }
//    }
}
